package com.securitydemo.config;


import com.securitydemo.config.security.JwtAuthenticationTokenFilter;
import com.securitydemo.config.security.provider.HYAbstractUserDetailsAuthenticationProvider;
import com.securitydemo.securitylogin.JwtAccessDeniedHandler;
import com.securitydemo.securitylogin.JwtAuthenticationEntryPoint;
import com.securitydemo.securitylogin.JwtAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Autowired
    private JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler;

    /**
     * 针对http 请求的控制
     *
     * @param httpSecurity
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {


        /**
         * httpSecurity
         *                 .formLogin()
         *                 //自定义认证成功处理器
         *                 .successHandler(jwtAuthenticationSuccessHandler)
         *                 // 自定义失败拦截器
         *                 .failureHandler(loginFailureHandler)
         *                 // 自定义登录拦截URI
         *                 .loginProcessingUrl("/login")
         *                 .and()
         *                 //token的验证方式不需要开启csrf的防护
         *                 .csrf().disable()
         *                 // 自定义认证失败类
         *                 .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
         *                 // 自定义权限不足处理类
         *                 .accessDeniedHandler(jwtAccessDeniedHandler)
         *                 .and()
         *                 //设置无状态的连接,即不创建session
         *                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
         *                 .authorizeRequests()
         *                 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
         *                 .antMatchers("/login").permitAll()
         *                 //配置允许匿名访问的路径
         *                 .anyRequest().authenticated();
         *         // 解决跨域问题（重要）  只有在前端请求接口时才发现需要这个
         *         httpSecurity.cors().and().csrf().disable();
         */


        // 跨站点访问请求。。在winFrom 中需要关闭，如果只用JWT 请求
        httpSecurity.csrf().disable();
        // frame 嵌套配置。默认关闭，允许页面嵌套
        httpSecurity.headers().frameOptions().disable();
        // 开启跨域
        httpSecurity.cors();

        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        httpSecurity
                .authorizeRequests()
                // 放行所有swagger
                .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui",
                        "/swagger-resources", "/swagger-resources/configuration/security",
                        "/swagger-ui/**", "/webjars/**", "/login/**", "/test/**", "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js").permitAll().antMatchers("/profile/**").anonymous()
                .antMatchers("/common/download**").anonymous()
                .antMatchers("/common/download/resource**").anonymous()
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/webjars/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                .antMatchers("/druid/**").anonymous()
                .anyRequest().authenticated()
                .and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)
                .and().formLogin().loginProcessingUrl("login/token").successHandler(jwtAuthenticationSuccessHandler)
                //.and().formLogin().loginProcessingUrl("/login/token").successHandler(jwtAuthenticationSuccessHandler)
                .and().exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
                    authException.printStackTrace();
                    response.getWriter().write("login fail");
                });

        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 指定UserDetailService和加密器
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
        auth.authenticationProvider(hyAbstractUserDetailsAuthenticationProvider());
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        AuthenticationManager authenticationManager = super.authenticationManager();
        return super.authenticationManager();
    }

    @Bean
    public AuthenticationProvider hyAbstractUserDetailsAuthenticationProvider() {
        return new HYAbstractUserDetailsAuthenticationProvider();
    }
}
